#ifndef _COMMON_INTERFACE_H_
#define _COMMON_INTERFACE_H_

//NotifyID define
#define NT_SIGNAL                  1      // tTimer notify event id.
#define NT_OTHER                   100

#include "data_define/Result.h"
#include "data_define/InterfaceID.h"
#include "util.h"
#include <deque>
#include <map>

// Base interface for all other interface.
class IBaseInterface
{
public:
	/**
	 * Increase the reference to associated instance.
	 * Param:
	 *    strWho: The User Identifier.
	 **/
	virtual void AddRef(const char * strWho) = 0;

	/**
	 * Decrease the reference to associated instance.
	 * Param:
	 *    strWho: The User Identifier.
	 * Return:
	 *    RET_OK: Release operation success.
	 *    RET_ERROR: Can not Release it, strWho don't reference to associated instance.
	 **/
	virtual eResult Release(const char * strWho) = 0;

	/**
	 * Get the required interface by eIID.
	 * Param:
	 *    InterfaceID: The reqired interface identifier.
	 *    ppInterface: pointer to the interface.
	 *    strWho: The User Identifier.
	 * Return:
	 *    RET_OK: operation is successed, and ppInterface is updated. The reference count is 
	 *            increased and strWho is recorded.
	 *    RET_NO_INTERFACE: Interface you specified don't exist.
	 **/
	virtual eResult GetInterface(eIID InterfaceID, void ** ppInterface, const char * strWho) = 0;

	/**
	 * Get the current reference count of the instance.
	 **/
	virtual unsigned int RefCount() = 0;
};

//===================================================================
// This interface is used to notify other instance.
//-------------------------------------------------------------------
class IMsgNotify
{
public:
	virtual int NotifyMessage(int NotifyID, long Data1, long Data2, 
		void * DataPtr, int DataSize) = 0;
};


class tBaseInterface
{
protected:
	tMutex BaseMutex;
	char m_ModuleName[32];
	std::deque<char*> m_UserReference;
	std::map<eIID, void*> m_InterfaceMap;
public:
	tBaseInterface(const char* module_name)
	{
		//SetInterface(eIID_IBaseInterface, this);
		if (module_name)
		{
#ifndef _linux_
			lstrcpynA(m_ModuleName, module_name, 31);
#else
			strncpy(m_ModuleName, module_name, 31);
#endif
		}
		else
		{
#ifndef _linux_
			lstrcpynA(m_ModuleName, "Module", 31);
#else
			strncpy(m_ModuleName, "Module", 31);
#endif
		}
	}

	~tBaseInterface()
	{
#ifdef _DEBUG	
		DumpReference();
#endif
		for (unsigned int i = 0; i < m_UserReference.size(); i++)
		{
			delete[] m_UserReference[i];
		}
		m_UserReference.clear();
	}

	void SetInterface(eIID InterfaceID, void * pInterfacePtr)
	{
		m_InterfaceMap[InterfaceID] = pInterfacePtr;
	}

	void DumpReference()
	{
		if (!m_UserReference.empty())
		{
			for (unsigned int i = 0; i < m_UserReference.size(); i++)
			{
				DBGSTR2A("Warning: User[%s] still use %s.\n",
						m_UserReference[i], m_ModuleName);
			}
		}
	}

	virtual void AddRef(const char * strWho)
	{
		AUTO_MUTEX_2 lock(BaseMutex);
		char * str = new char[16];
		if (strWho != NULL)
		{
#ifndef _linux_
			lstrcpynA(str, strWho, 16);
#else
			strncpy(str, strWho, 16);
#endif
		}
		else
		{
#ifndef _linux_
			lstrcpynA(str, "unknown", 16);
#else
			strncpy(str, "unknown", 16);
#endif
		}
		m_UserReference.push_back(str);
	}
	virtual eResult Release(const char * strWho)
	{
		AUTO_MUTEX_2 lock(BaseMutex);
		std::deque<char*>::iterator it_user;
		std::deque<char*>::iterator it_end = m_UserReference.end();
		for (it_user = m_UserReference.begin(); it_user != it_end; it_user++)
		{
			if (strncmp((*it_user), strWho, 16-1) == 0)
			{
				delete[] (*it_user);
				m_UserReference.erase(it_user);
				return RET_OK;
			}
		}
		DBGSTR2A("Error to relesae the [%s], User [%s] can not be found.\n", 
					m_ModuleName, 
					strWho);
		return RET_ERROR;
	}
	virtual unsigned int RefCount()
	{
		AUTO_MUTEX_2 lock(BaseMutex);
		return (unsigned int)m_UserReference.size();
	}
	virtual eResult GetInterface(eIID InterfaceID, void ** ppInterface, const char * strWho)
	{
		*ppInterface = NULL;
		if (ppInterface == NULL || strWho == NULL)
			return RET_ERROR;
		std::map<eIID, void*>::iterator it_map = m_InterfaceMap.find(InterfaceID);
		if (it_map != m_InterfaceMap.end())
		{
			*ppInterface = it_map->second;
			AddRef(strWho);
			return RET_OK;
		}
		return RET_NO_INTERFACE;
	}

};
#define BASEINTERFACE_METHODS \
	void AddRef(const char * strWho){ tBaseInterface::AddRef(strWho);}\
	eResult Release(const char * strWho){ return tBaseInterface::Release(strWho);}\
	eResult GetInterface(eIID InterfaceID, void ** ppInterface, const char * strWho){ \
	return tBaseInterface::GetInterface(InterfaceID, ppInterface, strWho);}\
	unsigned int RefCount(){ return tBaseInterface::RefCount();}
#endif

